package com.tbit.uqbike.center.config.ThreadPoolConfig;

import com.alibaba.fastjson.JSONObject;

import com.tbit.uqbike.center.util.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义拒绝策略：抛弃最老的，重放最新的，并提供监控报警
 * @author Zhang Zhi Liang
 * @date 2024/4/22 10:34
 */
@Slf4j
@Component
public class MsgRejectedExecutionHandler implements RejectedExecutionHandler {
    /**
     * 上次企业微信预警发送时间
     */
    private volatile Long preSendMillis = 0L;
    /**
     * 预警间隔，毫秒  默认：2min
     */
    @Value("${wx.chat.robot.intervals:120000}")
    private Integer interval;
    /**
     * 群聊机器人 webhook 地址
     */
    @Value("${wx.chat.robot.url:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=452c277d-899e-4685-b9a2-06236c2c430f}")
    private String url;
    /** 平台名 */
    @Value("${uqbike.platform.name:nacos中未识别平台}")
    private String platformName;

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 触发抛弃 和 获取抛弃任务（这时队列别其他线程消费完毕了）之间的并发，不会产生影响
        // 抛弃最老的重新尝试执行新的任务
        Runnable failRunnable = null;
        if (!executor.isShutdown()) {
            failRunnable = executor.getQueue().poll();
            executor.execute(r);
        }
        // 对抛弃的任务的自定义处理
        if (failRunnable instanceof MsgRunnable) {
            MsgRunnable runnable = (MsgRunnable) failRunnable;
            synchronized (MsgRejectedExecutionHandler.class) {
                // 超过阈值再报警
                if ((System.currentTimeMillis() - preSendMillis) > interval) {
                    preSendMillis = System.currentTimeMillis();
                    sendVxAlarm(runnable.getMessage());
                }
            }
        }
    }

    /**
     * 企业微信群聊机器人报警消息推送
     */
    private void sendVxAlarm(String msg) {

        JSONObject object = new JSONObject();
        object.put("msgtype", "text");
        JSONObject subObject = new JSONObject();
        subObject.put("content", String.format("[%S] 因消息堆积，MQ消息[%s]被线程池任务丢列抛弃，请及时处理!",platformName, msg));
        object.put("text", subObject);
        try {
            HttpClientUtils.httpJson(url, object.toJSONString());
        } catch (IOException e) {
            log.error("Json转化失败了喔！",e);
        }
    }
}
